package itsm.isperp.framework.template;

import java.io.*;
import java.net.URL;
import java.util.Map;

/**
 * 一个用于解析字符串的模板，根据是设置的source以及上下文的context，对输入文本定于的变量进行解析
 * 
 * <p>
 * <ul>
 * <li>1、支持普通变量解析；</li>
 * <li>2、支持列表形式解析：[#list var as item] ${item.name} [/#list];</li>
 * <li>3、支持对变量日期format方法及列表的size方法的解析：List<String> s;${s?size}</li>
 * <li>4、支持对象的无参数方法，但不支持方法推导（如map.keySet.length），如Map的keySet，size：Map
 * m;${map.size} ；</li>
 * </ul>
 * </p>
 * 
 * @author lizx
 * @date 2013-9-1
 * @since 1.0
 * 
 */
public class Template implements Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private String source;

	private Map<String, Object> context;

	public Template(String source) {
		this.source = source;
	}

	public Template() {

	}

	public Template(String source, Map<String, Object> context) {
		this.source = source;
		this.context = context;
	}

	public Template(InputStream source, Map<String, Object> context)
			throws IOException {
		this.source = readFromInputStream(source);
		this.context = context;
	}

	public Template(URL source, Map<String, Object> context) throws IOException {
		this.source = readFromInputStream(source.openStream());
		this.context = context;
	}

	public Template(File source, Map<String, Object> context)
			throws IOException {
		this.source = readFromInputStream(new FileInputStream(source));
		this.context = context;
	}

	private String readFromInputStream(InputStream in) throws IOException {
		StringBuilder s = new StringBuilder();
		BufferedReader reader = new BufferedReader(new InputStreamReader(in));
		String read;
		while ((read = reader.readLine()) != null)
			s.append(read).append("\n");
		return s.toString();
	}

	/**
	 * 渲染结果内容
	 * 
	 * @return 结果内容
	 * @throws TemplateException
	 */
	public String render() throws TemplateException {
		String result = new TemplateParser(this).render();
		this.source = null;
		return result;
	}

	public String render(String str) throws TemplateException {
		this.source = str;
		String result = new TemplateParser(this).render();
		this.source = null;
		return result;
	}

	public boolean equals(Object o) {
		if (this == o)
			return true;
		if (o == null || getClass() != o.getClass())
			return false;

		Template template = (Template) o;

		return !(source != null ? !source.equals(template.source)
				: template.source != null);
	}

	public int hashCode() {
		return source != null ? source.hashCode() : 0;
	}

	public String getSource() {
		return source;
	}

	public void setSource(String source) {
		this.source = source;
	}

	public Map<String, Object> getContext() {
		return context;
	}

	public void setContext(Map<String, Object> context) {
		this.context = context;
	}
}